import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_sound_record/flutter_sound_record.dart';
import 'package:get/get.dart';
import 'package:jump_scape/js_config.dart';
import 'package:jump_scape/js_ui/js_dialog/js_personal.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';

import 'js_audio_play.dart';

class JsAudioRecorder {
  static final JsAudioRecorder _instance = JsAudioRecorder._internal();
  JsAudioRecorder._internal();
  factory JsAudioRecorder() => _instance;

  String tempFileName = "";
  int tempStartDuration = 0;

  FlutterSoundRecord? _audioRecorder;

  bool isRecording() => _audioRecorder != null;

  Function(List<dynamic>) _onRecordFinish = (_) {};

  // 初始化录音
  Future<void> startRecording(BuildContext context, Function(List<dynamic>) onRecordFinish) async {
    await JsAudioPlay().stopPlayer();

    final has = await getPermissionStatus(context);
    if (!has) {
      onRecordFinish([]);
      return;
    }

    _onRecordFinish = onRecordFinish;
    if (isRecording()) return;

    try {
      final fileExtension = GetPlatform.isAndroid ? '.aac' : '.aac';
      final fileName = "${DateTime.now().millisecondsSinceEpoch}$fileExtension";
      tempFileName = fileName;
      tempStartDuration = DateTime.now().millisecondsSinceEpoch;
      final tempDir = await getTemporaryDirectory();
      String path = File('${tempDir.path}/$fileName').path;

      final exists = await File(path).exists();
      debugPrint('[录音] 开始 path=$path exists=$exists');

      try {
        _audioRecorder = FlutterSoundRecord();
        await _audioRecorder?.start(path: path);
      } catch (e) {
        e.printError();
      }

      while (isRecording()) {
        await Future.delayed(const Duration(milliseconds: 20));
        int duration = DateTime.now().millisecondsSinceEpoch - tempStartDuration;
        if (duration >= 10 * 1000) {
          endRecording();
          return;
        }
      }
    } catch (err) {
      debugPrint('[录音] 错误 $err');
      cancelRecording();
    }
  }

  Future<void> cancelRecording() async {
    try {
      final String? path = await _audioRecorder?.stop();
      int length = 0;
      bool exists = false;
      if (path != null && path.isNotEmpty) {
        final file = File(path);
        length = await file.length();
        await file.delete();
        exists = await file.exists();
      }

      debugPrint('[录音] 结束 path=$path, exists=$exists, length=$length');
    } catch (e) {
      e.printError();
    }
    _stopRecording();
  }

  Future<void> endRecording() async {
    final String? path = await _audioRecorder?.stop();
    int length = 0;
    bool exists = false;
    int duration = DateTime.now().millisecondsSinceEpoch - tempStartDuration;
    if (path != null && path.isNotEmpty) {
      final file = File(path);
      length = await file.length();
      exists = await file.exists();
    }

    if (exists) {
      _onRecordFinish(["${JsApp.fileToTempName}/$tempFileName", duration]);
    } else {
      _onRecordFinish([]);
    }

    debugPrint('[录音] 结束 path=$path, length=$length, exists=$exists, duration=$duration');
    _stopRecording();
  }

  // 停止录音
  Future<void> _stopRecording() async {
    try {
      await _audioRecorder?.dispose();
    } catch (_) {}
    _audioRecorder = null;
  }

  Future<bool> getPermissionStatus(BuildContext context) async {
    Permission permission = Permission.microphone;
    PermissionStatus status = await permission.status;
    if (status.isGranted) {
      return true;
    }

    if (status.isDenied) {
      // 被拒绝
      requestPermission(context, permission);
    } else if (status.isPermanentlyDenied) {
      // 拒绝且不在提示
      if (context.mounted) {
        jsShowRequiresMicrophoneDialog(context);
      }
    } else if (status.isRestricted) {
      requestPermission(context, permission);
    } else {
      if (context.mounted) {
        jsShowRequiresMicrophoneDialog(context);
      }
    }
    return false;
  }

  void requestPermission(BuildContext context, Permission permission) async {
    PermissionStatus status = await permission.request();
    if (status.isPermanentlyDenied) {
      if (context.mounted) {
        jsShowRequiresMicrophoneDialog(context);
      }
    }
  }
}
